const body = document.querySelector('body');

// 虚拟DOM，提高渲染效率
const fg = document.createDocumentFragment();

// 不可拖拽区域
let area = document.createElement('div');
area.style.position = 'absolute';
area.style.width = '777px';
area.style.height = '777px';
area.style.zIndex = '-777';
area.style.borderRadius = '50%';
area.style.backgroundColor = 'rgba(0, 0, 0, .1)';
fg.appendChild(area);

// 中心定位
let center = document.createElement('div');
center.style.position = 'absolute';
center.style.transformStyle = 'preserve-3d';
fg.appendChild(center);

body.appendChild(fg);

// 防止出bug
let screen = document.createElement('div');
screen.style.position = 'absolute';
screen.style.width = '100%';
screen.style.height = '100%';
screen.style.zIndex = '-999';

body.appendChild(screen);

let oldX, oldY, angleX = 30,
    angleY = -30;

center.style.transform = `rotateX(${angleY}deg) rotateY(${angleX}deg)`;

// 添加拖动事件
screen.addEventListener('mousedown', e => {
    screen.style.zIndex = '999';
    oldX = e.x;
    oldY = e.y;
    center.style.transition = null;
    screen.addEventListener('mousemove', rotateBox);
})
// 删除拖动事件
screen.addEventListener('mouseup', e => {
    screen.style.zIndex = '-999';
    screen.removeEventListener('mousemove', rotateBox);
    angleX = 30;
    angleY = -30;
    center.style.transform = `rotateX(${angleY}deg) rotateY(${angleX}deg)`;
    center.style.transition = 'all .5s ease';
    oldX = null;
    oldY = null;
})

// 拖动事件
function rotateBox(e) {
    let gapX = e.x - oldX;
    let gapY = e.y - oldY;
    if (gapX % 2 == 0 || gapY % 2 == 0) {
        angleX = (angleX % 360) + gapX;
        angleY = (angleY % 360) - gapY;
        oldX = e.x;
        oldY = e.y;
        center.style.transform = `rotateX(${angleY}deg) rotateY(${angleX}deg)`;
    }
}

let coordinate = [-100, 0, 100];

let EachSide = ['front', 'back', 'left', 'right', 'top', 'bottom'];

let sideType = {
    front: {
        transform: 'translate3d(-50%, -50%, 50px)',
        backgroundColor: 'white'
    },
    back: {
        transform: 'translate3d(-50%, -50%, -50px)',
        backgroundColor: 'yellow'
    },
    left: {
        transform: 'translate3d(-100%, -50%, 0) rotateY(90deg)',
        backgroundColor: 'red'
    },
    right: {
        transform: 'translate3d(0, -50%, 0) rotateY(90deg)',
        backgroundColor: 'orange'
    },
    top: {
        transform: 'translate3d(-50%, -100%, 0) rotateX(90deg)',
        backgroundColor: 'green'
    },
    bottom: {
        transform: 'translate3d(-50%, 0, 0) rotateX(90deg)',
        backgroundColor: 'blue'
    },
}

let YSide = ['front', 'right', 'back', 'left'];
let XSide = ['front', 'top', 'back', 'bottom'];
let ZSide = ['left', 'top', 'right', 'bottom'];
let turnSide = {
    XSide,
    YSide,
    ZSide
}

// 魔方建模
for (let x = 0; x < 3; x++) {
    for (let y = 0; y < 3; y++) {
        for (let z = 0; z < 3; z++) {
            // 创建子块
            let eachCenter = createEach(x, y, z);
            center.appendChild(eachCenter);
        }
    }
}

// 创建子块
function createEach(x, y, z) {
    let eachCenter = document.createElement('div');
    eachCenter.angle = 0;
    eachCenter.style.position = 'absolute';
    eachCenter.style.transformStyle = 'preserve-3d';
    eachCenter.style.transition = 'all .5s ease';
    eachCenter.addEventListener('transitionend', tEnd.bind(eachCenter));
    // 子块定位
    eachCenter.style.transform = `translate3d(${coordinate[x]}px, ${coordinate[y]}px, ${coordinate[z]}px)`;
    eachCenter.style.transformOrigin = `${-coordinate[x]}px ${-coordinate[y]}px ${-coordinate[z]}px`;
    // 子块面
    for (let i = 0; i < EachSide.length; i++) {
        eachCenter.appendChild(createEachSide(EachSide[i], x, y, z));
    }
    eachCenter.position = { x, y, z };
    return eachCenter;
}

// 重定位
function tEnd() {
    this.style.transition = '';
    this.style.transform = `translate3d(${coordinate[this.position.x]}px, ${coordinate[this.position.y]}px, ${coordinate[this.position.z]}px)`;
    this.style.transformOrigin = `${-coordinate[this.position.x]}px ${-coordinate[this.position.y]}px ${-coordinate[this.position.z]}px`;
    this.childNodes.forEach(el => {
        if(el.angle != 0) {
            let index = turnSide[el.turnSide].indexOf(el.direction);
            if (index != -1) {
                el.direction = turnSide[el.turnSide][(index + el.angle + 4) % 4];
                el.style.transform = sideType[el.direction].transform;
            }
            el.angle = 0;
        }
    })
    setTimeout(()=> {
        this.style.transition = 'all .5s ease';
        area.style.zIndex = '-777';
    }, 0)
}

// 创建子块每个面
function createEachSide(side, x, y, z) {
    let eachSide = document.createElement('div');
    eachSide.style.position = 'absolute';
    eachSide.style.width = '100px';
    eachSide.style.height = '100px';
    eachSide.style.border = '5px solid black';
    eachSide.style.transform = sideType[side].transform;
    eachSide.style.backgroundColor = sideType[side].backgroundColor;
    eachSide.direction = side;
    eachSide.angle = 0;
    eachSide.turnSide = null;
    eachSide.coordinate = { x, y, z };
    // 绕X\Y轴转
    eachSide.addEventListener('click', sideMouseClick);
    // 绕Z轴转
    eachSide.addEventListener('mousedown', sideMouseDown);
    eachSide.addEventListener('mouseup', sideMouseUp);
    return eachSide;
}

let clickFlag = false;
// 用于旋转层确定
let beforePosition = {}, afterPosition = {};
// 用于旋转面确定

// 每个面的点击事件--设计用于旋转
function sideMouseClick(e) {
    if(!clickFlag) {
        area.style.backgroundColor = 'rgba(255, 0, 0, .1)';
        beforePosition = this.parentNode.position;
        clickFlag = !clickFlag;
    }else if (clickFlag) {
        area.style.backgroundColor = 'rgba(0, 0, 0, .1)';
        afterPosition = this.parentNode.position;
        clickFlag = !clickFlag;
        // 确保同面操作
        if(beforePosition.x != afterPosition.x && beforePosition.z != afterPosition.z && beforePosition.z != afterPosition.z) return;
        // 旋转轴确认，旋转方向确认
        let xGap = afterPosition.x - beforePosition.x;
        let yGap = afterPosition.y - beforePosition.y;
        let zGap = afterPosition.z - beforePosition.z;
        if (xGap != 0 && yGap == 0) {
            // 最后一排反向
            xGap = beforePosition.z == 0 ? -xGap : xGap;
            rotateByY(xGap > 0 ? 1 : -1, beforePosition.y);
        }else if (xGap == 0 && yGap != 0) {
            yGap = beforePosition.z == 0 ? -yGap : yGap;
            rotateByX(yGap > 0 ? 1 : -1, beforePosition.x);
        }else if (zGap != 0 && beforePosition.y == 0) {
            rotateByX(zGap > 0 ? 1 : -1, beforePosition.x);
        }else if (zGap != 0 && beforePosition.x == 0) {
            rotateByY(zGap > 0 ? 1 : -1, beforePosition.y);
        }
    }
};

let _beforePosition = null;
let _afterPosition = null;

function sideMouseDown() {
    if(clickFlag) return;
    area.style.backgroundColor = 'rgba(255, 0, 0, .1)';
    _beforePosition = this.parentNode.position;
}

function sideMouseUp() {
    if(clickFlag) return;
    area.style.backgroundColor = 'rgba(0, 0, 0, .1)';
    _afterPosition = this.parentNode.position;
    if(_beforePosition.x != _afterPosition.x && _beforePosition.z != _afterPosition.z && _beforePosition.z != _afterPosition.z) return;
    let xGap = _afterPosition.x - _beforePosition.x;
    let yGap = _afterPosition.y - _beforePosition.y;
    let zGap = _afterPosition.z - _beforePosition.z;
    if(zGap == 0 && xGap != 0) {
        area.style.zIndex = '777';
        xGap = _beforePosition.y == 2 ? -xGap : xGap;
        rotateByZ(xGap > 0 ? 1 : -1, _beforePosition.z);
    }else if (zGap == 0 && yGap != 0) {
        area.style.zIndex = '777';
        yGap = _beforePosition.x == 2 ? -yGap : yGap;
        rotateByZ(yGap > 0 ? -1 : 1, _beforePosition.z);
    }
}

// 绕X轴旋转
function rotateByX(angle, x) {
    let even = [{y: 0, z: 0}, {y: 0, z: 2}, {y: 2, z: 2}, {y: 2, z: 0}];
    let odd = [{y: 0, z: 1}, {y: 1, z: 2}, {y: 2, z: 1}, {y: 1, z: 0}];
    let parity = [even, odd];
    center.childNodes.forEach( el => {
        if(el.position.x != x) return;
        // 旋转
        el.angle = angle;
        el.childNodes.forEach(el => {
            el.angle = angle * -1;
            el.turnSide = 'XSide';
        })
        el.style.transform =
            `translate3d(${coordinate[el.position.x]}px, ${coordinate[el.position.y]}px, ${coordinate[el.position.z]}px) rotateX(${-el.angle * 90}deg)`;
        // 改变eachCenter的position
        let stamp = (el.position.y + el.position.z) % 2;
        let item = parity[stamp].find( item => {
            return item.y == el.position.y && item.z == el.position.z;
        })
        // 排除中心点
        if(item) {
            let index = parity[stamp].indexOf(item);
            el.position.y = parity[stamp][(index + angle + 4) % 4].y;
            el.position.z = parity[stamp][(index + angle + 4) % 4].z;
        }
    })
}

// 绕Y轴旋转
function rotateByY(angle, y) {
    let even = [{x: 0, z: 0}, {x: 0, z: 2}, {x: 2, z: 2}, {x: 2, z: 0}];
    let odd = [{x: 0, z: 1}, {x: 1, z: 2}, {x: 2, z: 1}, {x: 1, z: 0}];
    let parity = [even, odd];
    center.childNodes.forEach( el => {
        if(el.position.y != y) return;
        // 旋转
        el.angle = angle;
        el.childNodes.forEach(el => {
            el.angle = angle;
            el.turnSide = 'YSide';
        })
        el.style.transform =
            `translate3d(${coordinate[el.position.x]}px, ${coordinate[el.position.y]}px, ${coordinate[el.position.z]}px) rotateY(${el.angle * 90}deg)`;
        // 改变eachCenter的position
        let stamp = (el.position.x + el.position.z) % 2;
        let item = parity[stamp].find( item => {
            return item.x == el.position.x && item.z == el.position.z;
        })
        // 排除中心点
        if(item) {
            let index = parity[stamp].indexOf(item);
            el.position.x = parity[stamp][(index + angle + 4) % 4].x;
            el.position.z = parity[stamp][(index + angle + 4) % 4].z;
        }
    })
}

// 绕Z轴旋转
function rotateByZ(angle, z) {
    let even = [{x: 0, y: 0}, {x: 2, y: 0}, {x: 2, y: 2}, {x: 0, y: 2}];
    let odd = [{x: 0, y: 1}, {x: 1, y: 0}, {x: 2, y: 1}, {x: 1, y: 2}];
    let parity = [even, odd];
    center.childNodes.forEach( el => {
        if(el.position.z != z) return;
        // 旋转
        el.angle = angle;
        el.childNodes.forEach(el => {
            el.angle = angle;
            el.turnSide = 'ZSide';
        })
        el.style.transform =
            `translate3d(${coordinate[el.position.x]}px, ${coordinate[el.position.y]}px, ${coordinate[el.position.z]}px) rotateZ(${el.angle * 90}deg)`;
        // 改变eachCenter的position
        let stamp = (el.position.x + el.position.y) % 2;
        let item = parity[stamp].find( item => {
            return item.x == el.position.x && item.y == el.position.y;
        })
        // 排除中心点
        if(item) {
            let index = parity[stamp].indexOf(item);
            el.position.x = parity[stamp][(index + angle + 4) % 4].x;
            el.position.y = parity[stamp][(index + angle + 4) % 4].y;
        }
    })
}